import sys
import time
import traceback
from functools import wraps

import requests

from src.exceptions import AllViewsExceptions
from src.singletone.session_singleton import SessionSingleton

session_singleton = SessionSingleton()


# 错误捕捉&重试装饰器
def exc_decorator(**kwargs):
    def deco(func):
        @wraps(func)
        async def wrapper(*args, **_kwargs):
            func_name = func.__name__
            try:
                return await func(*args, **_kwargs)
            except Exception as e:
                # 没啥用的变量,为了不显示警告而已
                del e
                # 获取错误类型,值,栈
                exc_type, ex_val, ex_stack = sys.exc_info()
                # 获取指定要重试的错误类型,默认是requests.exceptions.RequestException
                sender_exc_typies = kwargs.get("retry_exceptions", (requests.exceptions.RequestException,))
                # 最大重试次数,默认是3次
                max_retries = kwargs.get("max_retries", 3)
                # 重试延迟,默认0s
                delay = kwargs.get("delay", 0)
                local_count = 0
                # 根据条件开始重试
                if exc_type in sender_exc_typies:
                    while local_count < max_retries:
                        try:
                            return func(*args, **_kwargs)
                        except exc_type as e:
                            print(str(e) + "in {}".format(func_name))
                            local_count += 1
                            # 如果重试了指定次数还不行,则直接判定异常
                            if local_count == max_retries:
                                raise AllViewsExceptions("maximum retries in {},quit now!".format(func_name))
                            time.sleep(delay)
                else:
                    from src.singletone.error_msg_singleton import ErrorMsg
                    format_exc = traceback.format_exc()
                    print(format_exc)
                    print("An exception occur in {func_name} : {detail}".format(func_name=func_name, detail=format_exc))
                    error = ErrorMsg()
                    error.error_msg = {func.__name__: {"status": False, "reason": ex_val.args[0]}}
                    raise AllViewsExceptions(ex_val)

        return wrapper

    return deco


# 检查session装饰器
def check_session_decorator(func):
    @wraps(func)
    async def check_session_wrapper(*args, **kwargs):
        # 10分钟内都不需要更新session
        if (int(time.time()) * 1000 - session_singleton.session_build_time) > 1000 * 10 * 60:
            session = session_singleton.session
            response = session.get("http://132.110.64.76:8080/allview/index.jsp")

            if "登陆超时" in response.text or "请输入登录信息" in response.text:
                await rebuild_session()
        # 刷新session有效时间
        session_singleton.session_build_time = int(time.time() * 1000)
        return await func(*args, **kwargs)

    return check_session_wrapper


# 填充post参数装饰器
def fill_up_args_decorator(func):
    @wraps(func)
    async def fill_up_args_wrapper(*args, **kwargs):
        from src.allview.functions import build_poster
        poster = build_poster(kwargs, func.__name__)
        return await func(*args, **poster)

    return fill_up_args_wrapper


def error_msg_decorator(func):
    @wraps(func)
    async def error_msg_wrapper(*args, **kwargs):
        from src.singletone.error_msg_singleton import ErrorMsg
        f = await  func(*args, **kwargs)
        error = ErrorMsg()
        error.error_msg = {func.__name__: {"status": True, "reason": ""}}
        return f

    return error_msg_wrapper


# 重新获取session
@exc_decorator(retry_exceptions=(requests.exceptions.RequestException, ValueError), max_retries=5)
async def rebuild_session(**kwargs):
    session = session_singleton.session
    session = session if session else requests.session()
    username = kwargs.get("username", "13392790627")
    password = kwargs.get("password", "123456789")
    captcha = kwargs.get("captcha", "111111")
    post = {
        "ISMOBILE": "false",
        "YGGH": username,
        "YGMM": password,
        "yzm": captcha,
    }
    from src.common.constant import PROJECT_URL
    response = session.post(PROJECT_URL['login'], data=post, timeout=30)
    if "欢迎回来" not in response.text:
        raise ValueError("Login failed,please check your username and password")
    return session
